//
//  AppDelegate.m
//  Pennyworth
//
//  Created by Chris Karr on 12/24/07.
//  Copyright 2007 Chris J. Karr. All rights reserved.
//

#import <Security/Security.h>

#import "AnalyticsLogger.h"
#import "AppDelegate.h"
#import "AppleScriptPrediction.h"
#import "Observation.h"

#include "LoginItemsAE.h"

#define START_AT_LOGIN @"start_at_login"

@implementation AppDelegate

- (AppDelegate *) init
{
	if (self = [super init])
		sensorsLoaded = NO;
	
	return self;
}

- (void) activateStatusMenu
{
    NSStatusBar * bar = [NSStatusBar systemStatusBar];
 
    theItem = [bar statusItemWithLength:NSVariableStatusItemLength];
    [theItem retain];
 
    [theItem setTitle:nil];
    [theItem setImage:[NSImage imageNamed:@"bell-small"]];
    [theItem setAlternateImage:[NSImage imageNamed:@"bell-small-alt"]];
    [theItem setHighlightMode:YES];
    [theItem setMenu:menu];
}

- (void) hotKeyReleased:(NDHotKeyEvent *) aHotKey
{
	NSDictionary * postObject = [NSDictionary dictionaryWithObjectsAndKeys:@"Prediction Correction (Hot Key)", ANALYTIC_NAME, @"", ANALYTIC_VALUE, nil];
	
	[[NSNotificationCenter defaultCenter] postNotificationName:ANALYTIC_EVENT object:postObject];
	
	[trainingManager correctTraining:nil];
}

- (void) awakeFromNib
{
	if (!sensorsLoaded)
	{
		sensorsLoaded = YES;

		[NDHotKeyEvent setSignature:'PWth'];

		hotKey = [[NDHotKeyEvent hotKeyWithKeyCode:8 character:99 modifierFlags:(NSControlKeyMask|NSCommandKeyMask)] retain];
		[hotKey setTarget:self selectorReleased:@selector(hotKeyReleased:) selectorPressed:@selector(hotKeyReleased:)];
		[hotKey setEnabled:YES];
		
		[self activateStatusMenu];
	
		if (![NSBundle loadNibNamed:@"Sensors" owner:self])
			NSLog (@"Warning! Could not load Sensors XIB file.\n");
	
		NSSortDescriptor * descriptor = [[NSSortDescriptor alloc] initWithKey:@"sensor" ascending:YES];
		[observations setSortDescriptors:[NSArray arrayWithObject:descriptor]];
		[descriptor release];
	}
	
	[[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:START_AT_LOGIN options:0 context:NULL];
	[[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"Pennyworth Launched" object:[[NSBundle mainBundle] bundleIdentifier]];
}

- (void) startAtLogin
{
	BOOL enabled = [[NSUserDefaults standardUserDefaults] boolForKey:START_AT_LOGIN];
	
	OSStatus status;
	CFArrayRef loginItems = NULL;
	NSURL * url = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
	
	int existingLoginItemIndex = -1;
	
	status = LIAECopyLoginItems (&loginItems);
	
	if (status == noErr) 
	{
		NSEnumerator * enumerator = [(NSArray *) loginItems objectEnumerator];
		NSDictionary * loginItemDict;
		
		while ((loginItemDict = [enumerator nextObject])) 
		{
			if ([[loginItemDict objectForKey:(NSString *) kLIAEURL] isEqual:url]) 
			{
				existingLoginItemIndex = [(NSArray *) loginItems indexOfObjectIdenticalTo:loginItemDict];
				break;
			}
		}
	}
	
	if (enabled && (existingLoginItemIndex == -1))
	{
		NSDictionary * postObject = [NSDictionary dictionaryWithObjectsAndKeys:@"Enabled Start At Login", ANALYTIC_NAME, @"", ANALYTIC_VALUE, nil];
		[[NSNotificationCenter defaultCenter] postNotificationName:ANALYTIC_EVENT object:postObject];
		
		LIAEAddURLAtEnd ((CFURLRef) url, false);
	}
	else if (!enabled && (existingLoginItemIndex != -1))
	{
		NSDictionary * postObject = [NSDictionary dictionaryWithObjectsAndKeys:@"Disabled Start At Login", ANALYTIC_NAME, @"", ANALYTIC_VALUE, nil];
		[[NSNotificationCenter defaultCenter] postNotificationName:ANALYTIC_EVENT object:postObject];
		LIAERemove (existingLoginItemIndex);
	}
	
	if (loginItems)
		CFRelease (loginItems);
}
	
- (void) observeValueForKeyPath: (NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
	if ([keyPath isEqual:START_AT_LOGIN])
		[self startAtLogin];
}
		

- (IBAction) predictions:(id) sender
{
	if ([predictionPanel isKeyWindow])
		[predictionPanel orderOut:sender];
	else
	{
		NSDictionary * postObject = [NSDictionary dictionaryWithObjectsAndKeys:@"Opened Predictions Window", ANALYTIC_NAME, @"", ANALYTIC_VALUE, nil];
		[[NSNotificationCenter defaultCenter] postNotificationName:ANALYTIC_EVENT object:postObject];

		[NSApp activateIgnoringOtherApps:YES];
		[predictionPanel makeKeyAndOrderFront:sender];
	}
}

- (IBAction) observations:(id) sender
{
	if ([observationWindow isKeyWindow])
		[observationWindow orderOut:sender];
	else
	{
		NSDictionary * postObject = [NSDictionary dictionaryWithObjectsAndKeys:@"Opened Observations Window", ANALYTIC_NAME, @"", ANALYTIC_VALUE, nil];
		[[NSNotificationCenter defaultCenter] postNotificationName:ANALYTIC_EVENT object:postObject];

		[NSApp activateIgnoringOtherApps:YES];
		[observationWindow makeKeyAndOrderFront:sender];
	}
}

- (IBAction) preferences:(id) sender
{
	if ([preferencesWindow isKeyWindow])
		[preferencesWindow orderOut:sender];
	else
	{
		NSDictionary * postObject = [NSDictionary dictionaryWithObjectsAndKeys:@"Opened Preferences Window", ANALYTIC_NAME, @"", ANALYTIC_VALUE, nil];
		[[NSNotificationCenter defaultCenter] postNotificationName:ANALYTIC_EVENT object:postObject];

		[NSApp activateIgnoringOtherApps:YES];
		[preferencesWindow makeKeyAndOrderFront:sender];
	}
}

- (IBAction) learners:(id) sender
{
	[learnerView refresh:sender];
	
	if ([learnersWindow isKeyWindow])
		[learnersWindow orderOut:sender];
	else
	{
		NSDictionary * postObject = [NSDictionary dictionaryWithObjectsAndKeys:@"Opened Learners Window", ANALYTIC_NAME, @"", ANALYTIC_VALUE, nil];
		[[NSNotificationCenter defaultCenter] postNotificationName:ANALYTIC_EVENT object:postObject];

		[NSApp activateIgnoringOtherApps:YES];
		[learnersWindow makeKeyAndOrderFront:sender];
	}
}


- (IBAction) rules:(id) sender
{
	if ([rulesWindow isKeyWindow])
		[rulesWindow orderOut:sender];
	else
	{
		NSDictionary * postObject = [NSDictionary dictionaryWithObjectsAndKeys:@"Opened Rules Window", ANALYTIC_NAME, @"", ANALYTIC_VALUE, nil];
		[[NSNotificationCenter defaultCenter] postNotificationName:ANALYTIC_EVENT object:postObject];

 		[NSApp activateIgnoringOtherApps:YES];
		[rulesWindow makeKeyAndOrderFront:sender];
	}
}

- (IBAction) logs:(id) sender
{
	if ([logWindow isKeyWindow])
		[logWindow orderOut:sender];
	else
	{
		NSDictionary * postObject = [NSDictionary dictionaryWithObjectsAndKeys:@"Opened Logs Window", ANALYTIC_NAME, @"", ANALYTIC_VALUE, nil];
		[[NSNotificationCenter defaultCenter] postNotificationName:ANALYTIC_EVENT object:postObject];

		[NSApp activateIgnoringOtherApps:YES];
		[logWindow makeKeyAndOrderFront:sender];
	}
}

- (BOOL) application:(NSApplication *) sender delegateHandlesKey:(NSString *) key
{
	if ([key isEqualToString:@"observations"])
		return YES;
	else if ([key isEqualToString:@"predictions"])
		return YES;
	else if ([key isEqualToString:@"log"])
		return YES;

	return NO;
}

- (NSArray *) getObservations
{
	NSMutableArray * obsArray = [NSMutableArray array];

	for (Observation * observation in [observations arrangedObjects])
	{
		AppleScriptObservation * o = [[AppleScriptObservation alloc] init];
		
		[o setName:[observation sensor]];
		
		NSObject * ov = [observation observation];
		
		if ([ov isKindOfClass:[NSArray class]])
		{
			NSMutableString * valueString = [NSMutableString string];
			
			for (NSObject * obj in ((NSArray *) ov))
			{
				if ([valueString length] != 0)
					[valueString appendString:@";"];

				[valueString appendString:[obj description]];
			}

			[o setValue:valueString];
		}
		else
			[o setValue:[ov description]];
		
		[obsArray addObject:o];
	}
	
	return obsArray;
}

- (NSArray *) getPredictions
{
	NSMutableArray * predictions = [NSMutableArray array];

	AppleScriptPrediction * location = [[AppleScriptPrediction alloc] init];
	[location setName:@"Location"];
	[location setValue:user.location];
	[predictions addObject:location];
	
	[location release];

	AppleScriptPrediction * social = [[AppleScriptPrediction alloc] init];
	[social setName:@"Social Context"];
	[social setValue:user.social];
	[predictions addObject:social];
	
	[social release];

	AppleScriptPrediction * activity = [[AppleScriptPrediction alloc] init];
	[activity setName:@"Activity"];
	[activity setValue:user.activity];
	[predictions addObject:activity];
	
	[activity release];

	return predictions;
}

- (void) logObservation:(NSScriptCommand *) command
{
	// NSLog (@"log observation");
}

- (void)applicationWillTerminate:(NSNotification *)aNotification
{
	[[NSNotificationCenter defaultCenter] postNotificationName:TERMINATE_NOTIFICATION object:self];
}

- (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication *) sender
{
	[NSApp activateIgnoringOtherApps:YES];
	
	if (NSAlertAlternateReturn == NSRunAlertPanel (@"Quit Pennyworth?", @"Do you want to stop running Pennyworth? No new context predictions can be made after Pennyworth quits.", @"No", @"Yes", nil))
	{
		NSDictionary * postObject = [NSDictionary dictionaryWithObjectsAndKeys:@"Terminated Application", ANALYTIC_NAME, @"", ANALYTIC_VALUE, nil];
		[[NSNotificationCenter defaultCenter] postNotificationName:ANALYTIC_EVENT object:postObject];

		return YES;
	}
	
	NSDictionary * postObject = [NSDictionary dictionaryWithObjectsAndKeys:@"Cancelled Application Termination", ANALYTIC_NAME, @"", ANALYTIC_VALUE, nil];
	[[NSNotificationCenter defaultCenter] postNotificationName:ANALYTIC_EVENT object:postObject];

	return NO;
}

- (NSString *) notePassword
{
	UInt32 length = 256;
	void * password = NULL;
	
	OSStatus status = SecKeychainFindGenericPassword (NULL, strlen ("Pennyworth"), "Pennyworth", strlen ("Default"), "Default", &length, &password, NULL);

	NSString * kcPassword = nil;

	if (status == errSecItemNotFound)
		NSLog (@"No password. returning nil.");
	else if (status	== noErr)
	{
		NSData * passwordData = [NSData dataWithBytes:password length:length];
		
		kcPassword = [[[NSString alloc] initWithData:passwordData encoding:NSUTF8StringEncoding] autorelease];
	}
	else
		NSLog (@"error retrieving keychain password %d", status);
	
	SecKeychainItemFreeContent (NULL, password);
	
	return kcPassword;
}

- (void) setNotePassword:(NSString *) newPassword
{
	if (newPassword == nil)
		newPassword = @"";
	
	if ([self notePassword] == nil)
		SecKeychainAddGenericPassword (NULL, strlen ("Pennyworth"), "Pennyworth", strlen ("Default"), "Default", [newPassword length], [newPassword UTF8String], NULL);
	else
	{
		SecKeychainItemRef itemRef = NULL;
		
		SecKeychainFindGenericPassword (NULL, strlen ("Pennyworth"), "Pennyworth", strlen ("Default"), "Default", 0, NULL, &itemRef);
		
		SecKeychainItemModifyAttributesAndData (itemRef, NULL, [newPassword length], [newPassword UTF8String]);
	}
}

@end
